package com.herohead;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.Collection;

import cryptix.message.EncryptedMessage;
import cryptix.message.EncryptedMessageBuilder;
import cryptix.message.KeyBundleMessage;
import cryptix.message.LiteralMessage;
import cryptix.message.LiteralMessageBuilder;
import cryptix.message.Message;
import cryptix.message.MessageException;
import cryptix.message.MessageFactory;
import cryptix.message.NotEncryptedToParameterException;
import cryptix.openpgp.PGPArmouredMessage;
import cryptix.pki.KeyBundle;


public class PGP {

	static byte[] b;

	KeyBundle bundle = null;
	Message msg = null;
	MessageFactory mf = null;
	LiteralMessage litmsg = null;
	boolean armourFile = false;
	EncryptedMessage em = null;

	private void AddKey (String key) {

		try {

			FileInputStream in = new FileInputStream(key);

			MessageFactory mf = MessageFactory.getInstance("OpenPGP");
			@SuppressWarnings("rawtypes")
			Collection msgs = mf.generateMessages(in);

			KeyBundleMessage kbm = (KeyBundleMessage)msgs.iterator().next();

			bundle = kbm.getKeyBundle();

			in.close();

		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		} catch (NoSuchAlgorithmException nsae) {
			System.err.println("Cannot find the OpenPGP MessageFactory. "+
					"This usually means that the Cryptix OpenPGP provider is not "+
					"installed correctly.");
			nsae.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Reading keybundle failed.");
			me.printStackTrace();
			System.exit(-1);
		}
	}
	private byte[] armourMessage (Message msg) {

		try {
			PGPArmouredMessage armoured;
			armoured = new PGPArmouredMessage(msg);
			b = armoured.getEncoded();

		} catch (MessageException me) {
			System.err.println("Writing the encrypted message failed.");
			me.printStackTrace();
			System.exit(-1);
		}

		return b;
	}
	/**
	 * decrypt file
	 * @param fle2decrypt
	 * @param privKey
	 */
	public byte[] DecryptBytes (byte[] msgBytes, String privKey) {


		//**********************************************************************
		// Dynamically register both the Cryptix JCE and Cryptix OpenPGP
		// providers.
		//**********************************************************************
		java.security.Security.addProvider(new cryptix.jce.provider.CryptixCrypto() );
		java.security.Security.addProvider(new cryptix.openpgp.provider.CryptixOpenPGP() );


		//**********************************************************************
		// First read the key.
		//**********************************************************************
		KeyBundle bundle = null;
		MessageFactory mf = null;

		try {

			FileInputStream in = new FileInputStream(privKey);

			mf = MessageFactory.getInstance("OpenPGP");
			@SuppressWarnings("rawtypes")
			Collection msgs = mf.generateMessages(in);

			KeyBundleMessage kbm = (KeyBundleMessage)msgs.iterator().next();

			bundle = kbm.getKeyBundle();

			in.close();

		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		} catch (NoSuchAlgorithmException nsae) {
			System.err.println("Cannot find the OpenPGP MessageFactory. "+
					"This usually means that the Cryptix OpenPGP provider is not "+
					"installed correctly.");
			nsae.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Reading keybundle failed.");
			me.printStackTrace();
			System.exit(-1);
		}


		//**********************************************************************
		//  Read the message.
		//**********************************************************************
		EncryptedMessage em = null;

		try {


			//FileInputStream in = new FileInputStream(fle2decrypt);
			//			Collection msgs = mf.generateMessages(in);
			//			em = (EncryptedMessage)msgs.iterator().next();
			//
			//			in.close();


			DataInputStream in = new DataInputStream(new ByteArrayInputStream(msgBytes));
			//System.out.println(in.readLine());
			//ByteArrayInputStream in = new ByteArrayInputStream(msgBytes);
			@SuppressWarnings("rawtypes")
			Collection msgs = mf.generateMessages(in);
			em = (EncryptedMessage)msgs.iterator().next();
			in.close();




		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"Encrypt example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Reading message failed.");
			me.printStackTrace();
			System.exit(-1);
		}


		//**********************************************************************
		// Decrypt the message.
		//**********************************************************************
		try {

			//File fle = new File(fle2decrypt);

			//Store store = new Store();

			//store.setDir(fle.getParent()+ "/");

			Message msg = em.decrypt(bundle, "TestingPassphrase".toCharArray());

			//store.storeFile(((LiteralMessage)msg).getBinaryData(),filecheck(fle.getName()));

			//			System.out.println((LiteralMessage)msg);
			//			System.out.println(msg.getEncoded());

			//System.out.println(msg);
			//System.out.println(msg.getEncoded());

			b = (((LiteralMessage)msg).getBinaryData());
			//b = msg.getEncoded();


		} catch (NotEncryptedToParameterException netpe) {
			System.err.println("Not encrypted to this key.");
			netpe.printStackTrace();
			System.exit(-1);
		} catch (UnrecoverableKeyException uke) {
			System.err.println("Invalid passphrase.");
			uke.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Decrypting message failed.");
			me.printStackTrace();
			System.exit(-1);

		}

		return b;


		//catch (IOException me) {
		//	System.err.println("Decrypting message failed." + me);
		//	me.printStackTrace();
		//	System.exit(-1);
		//}
	}

	public byte[] DecryptFile (String fle2Decrypt) {

		System.out.println("here is the file to decrypt " + fle2Decrypt);

		try {
			File fle = new File(fle2Decrypt);
			byte[] msgBytes = Support.getBytesFromFile(fle);




			b = DecryptMessage(msgBytes);

		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
		return b;
	}

	public byte[] DecryptFileToBytes (String fle2decrypt, String privKey) {

		try {
			File fle = new File(fle2decrypt);
			byte[] msgBytes = Support.getBytesFromFile(fle);
			b = DecryptBytes(msgBytes, privKey);


		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
		return b;
	}

	public void DecryptFileToFile (String fle2decrypt, String privKey) {

		try {
			File fle = new File(fle2decrypt);
			byte[] msgBytes = Support.getBytesFromFile(fle);
			b = DecryptBytes(msgBytes, privKey);
			WriteFile(fle2decrypt + ".txta",b);

		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
	}
	private byte[] DecryptMessage (byte[] msgBytes) {

		System.out.println(msgBytes.length);

		try {
			DataInputStream in = new DataInputStream(new ByteArrayInputStream(msgBytes));
			System.out.println("After DataInputStream");

			@SuppressWarnings("rawtypes")
			Collection msgs = mf.generateMessages(in);

			System.out.println("After collection");
			em = (EncryptedMessage)msgs.iterator().next();
			in.close();
		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"Encrypt example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Reading message failed.");
			me.printStackTrace();
			System.exit(-1);
		} catch (Exception e) {
			System.err.println("Reading message failed." + e);
			e.printStackTrace();
			System.exit(-1);
		}

		//**********************************************************************
		// Decrypt the message.
		//**********************************************************************
		try {

			Message msg = em.decrypt(bundle, "TestingPassphrase".toCharArray());
			b = (((LiteralMessage)msg).getBinaryData());
		} catch (NotEncryptedToParameterException netpe) {
			System.err.println("Not encrypted to this key.");
			netpe.printStackTrace();
			System.exit(-1);
		} catch (UnrecoverableKeyException uke) {
			System.err.println("Invalid passphrase.");
			uke.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Decrypting message failed.");
			me.printStackTrace();
			System.exit(-1);

		}
		return b;
	}


	/**
	 * Encrypt File
	 * @param fle2encrypt
	 * @param pubKey
	 */

	public void Encrypt (String fle2encrypt, String pubKey) {

		//**********************************************************************
		// Dynamically register both the Cryptix JCE and Cryptix OpenPGP
		// providers.
		//**********************************************************************
		java.security.Security.addProvider(
				new cryptix.jce.provider.CryptixCrypto() );
		java.security.Security.addProvider(
				new cryptix.openpgp.provider.CryptixOpenPGP() );

		AddKey(pubKey);
		try {
			File fle = new File(fle2encrypt);
			byte[] msgBytes = Support.getBytesFromFile(fle);
			EncryptMessage(msgBytes);
			FileOutputStream out = new FileOutputStream(fle2encrypt + ".pgp");
			out.write(msg.getEncoded());
			out.close();

		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		} catch (MessageException ioe) {
			System.err.println("MessageException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
	}
	/**
	 * Encrypt bytes and return encrypted bytes
	 * @param msgBytes
	 * @param pubKey
	 * @return encrypted bytes
	 */
	public byte[] EncryptBytes (byte[] msgBytes, String pubKey) {
		//**********************************************************************
		// Dynamically register both the Cryptix JCE and Cryptix OpenPGP
		// providers.
		//**********************************************************************
		java.security.Security.addProvider(
				new cryptix.jce.provider.CryptixCrypto() );
		java.security.Security.addProvider(
				new cryptix.openpgp.provider.CryptixOpenPGP() );

		AddKey(pubKey);
		EncryptMessage(msgBytes);

		try {

			b = msg.getEncoded();
		} catch (MessageException me) {
			System.err.println("Reading message failed.");
			me.printStackTrace();
			System.exit(-1);
		}
		return b;
	}
	/**
	 * Encrypt Bytes to Bytes
	 * @param msgByte
	 * @param pubKey
	 * @return bytes
	 */
	public byte[] EncryptBytesToBytes (byte[] msgByte, String pubKey) {
		EncryptBytes(msgByte,pubKey);

		if (armourFile) {
			b = armourMessage(msg);
		} else {
			try {
				b = msg.getEncoded();
			} catch (MessageException ioe) {
				System.err.println("MessageException... You did remember to run the "+
						"GenerateAndWriteKey example first, right?");
				ioe.printStackTrace();
				System.exit(-1);
			}
		}
		return b;
	}

	/**
	 * Encrypt bytes and output to a File
	 * @param msgByte bytes
	 * @param pubKey full path to pub key
	 * @param fileToCreate
	 */

	public void EncryptBytesToFile (byte[] msgByte, String pubKey, String encryptName) {

		EncryptBytes(msgByte,pubKey);
		try {

			if (armourFile) {
				WriteFile(encryptName,armourMessage(msg));
			} else {
				WriteFile(encryptName,msg.getEncoded());
			}
		} catch (MessageException ioe) {
			System.err.println("MessageException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
	}
	/**
	 * Encrypt File
	 * 
	 * @param fle2encrypt
	 * @param pubKey
	 */

	private void EncryptFile (String fle2encrypt, String pubKey) {

		//**********************************************************************
		// Dynamically register both the Cryptix JCE and Cryptix OpenPGP
		// providers.
		//**********************************************************************
		java.security.Security.addProvider(
				new cryptix.jce.provider.CryptixCrypto() );
		java.security.Security.addProvider(
				new cryptix.openpgp.provider.CryptixOpenPGP() );

		AddKey(pubKey);
		try {
			File fle = new File(fle2encrypt);
			byte[] msgBytes = Support.getBytesFromFile(fle);
			EncryptMessage(msgBytes);

		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
	}
	/**
	 * Encrypt File to Bytes
	 * 
	 * @param fle2encrypt
	 * @param pubKey
	 * @return bytes
	 */

	public byte[] EncryptFileToBytes (String fle2encrypt, String pubKey) {

		try {
			EncryptFile(fle2encrypt,pubKey);
			if (armourFile) {
				b = armourMessage(msg);
			} else {
				b = msg.getEncoded();
			}
		} catch (MessageException ioe) {
			System.err.println("MessageException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
		return b;
	}
	/**
	 * encrypt File to File
	 * @param fle2encrypt
	 * @param pubKey
	 */
	public void EncryptFileToFile (String fle2encrypt, String pubKey) {

		try {
			EncryptFile(fle2encrypt,pubKey);
			if (armourFile) {
				WriteFile(fle2encrypt + ".pgp",armourMessage(msg));
			} else {
				WriteFile(fle2encrypt + ".pgp",msg.getEncoded());
			}
		} catch (MessageException ioe) {
			System.err.println("MessageException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
	}

	/**
	 * Encrypt file to filename that is passed.
	 * @param fle2encrypt
	 * @param pubKey
	 * @param encryptName
	 */

	public void EncryptFileToFile (String fle2encrypt, String pubKey, String encryptName) {

		try {
			EncryptFile(fle2encrypt,pubKey);
			if (armourFile) {
				WriteFile(encryptName,armourMessage(msg));
			} else {
				WriteFile(encryptName,msg.getEncoded());
			}
		} catch (MessageException ioe) {
			System.err.println("MessageException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
	}
	private void EncryptMessage (byte[] msgBytes) {
		//**********************************************************************
		//  Build the literal message.
		//**********************************************************************

		try {
			LiteralMessageBuilder lmb =	LiteralMessageBuilder.getInstance("OpenPGP");
			lmb.init(msgBytes);
			litmsg = (LiteralMessage)lmb.build();
		} catch (NoSuchAlgorithmException nsae) {
			System.err.println("Cannot find the OpenPGP LiteralMessageBuilder."+
					" This usually means that the Cryptix OpenPGP provider is not "+
					"installed correctly.");
			nsae.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Creating the literal message failed.");
			me.printStackTrace();
			System.exit(-1);
		}
		//**********************************************************************
		// Encrypt the message.
		//**********************************************************************
		try {

			EncryptedMessageBuilder emb = EncryptedMessageBuilder.getInstance("OpenPGP");
			emb.init(litmsg);
			emb.addRecipient(bundle);
			emb.setAttribute("compressed", "true");
			msg = emb.build();

		} catch (NoSuchAlgorithmException nsae) {
			System.err.println("Cannot find the OpenPGP "+
					"EncryptedMessageBuilder. "+
					"This usually means that the Cryptix OpenPGP provider is not "+
					"installed correctly.");
			nsae.printStackTrace();
			System.exit(-1);
		} catch (MessageException me) {
			System.err.println("Creating the encrypted message failed.");
			me.printStackTrace();
			System.exit(-1);
		}
	}

	/**
	 * filecheck
	 * @param fileName
	 * @return modified filename
	 */
	public String filecheck (String fileName) {

		if (fileName.endsWith(".pgp")) {
			return fileName.substring(0,fileName.length() - 4);
		}
		return fileName + ".decrypted";
	}

	public boolean GetArmour () {
		return armourFile;
	}
	public void SetArmour(boolean armourValue) {
		armourFile = armourValue;
	}

	/**
	 * Write File to disk
	 * @param fileName
	 * @param msgBytes
	 */

	private void WriteFile (String fileName, byte[] msgBytes) {
		try {

			FileOutputStream out = new FileOutputStream(fileName);
			out.write(msgBytes);
			out.close();
		} catch (IOException ioe) {
			System.err.println("IOException... You did remember to run the "+
					"GenerateAndWriteKey example first, right?");
			ioe.printStackTrace();
			System.exit(-1);
		}
	}
}
